// Copyright 2011 Jay Young. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview
 *
 * Provides a controller for driving the functionality needed to create a new
 * blog post.
 */

goog.provide('rb.publish.Publisher');

goog.require('goog.Disposable');
goog.require('goog.date.DateTime');
goog.require('goog.events');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventType');

goog.require('rb.post.BlogPost');
goog.require('rb.post.EventType');
goog.require('rb.post.PostEvent');
goog.require('rb.publish.PublishCommand');
goog.require('rb.publish.templates');
goog.require('rb.utils.dates');

goog.require('relief.utils');



/**
 * A controller whose job it is to drive the UI for publishing new blog posts.
 *
 * @param {rb.ServiceProvider} sp The app's service provider.
 * @constructor
 * @extends {goog.Disposable}
 */
rb.publish.Publisher = function(sp) {
  goog.base(this);

  /**
   * @type {rb.ServiceProvider}
   * @private
   */
  this.sp_ = sp;

  /**
   * @type {goog.events.EventHandler}
   * @private
   */
  this.handler_ = new goog.events.EventHandler(this);
};
goog.inherits(rb.publish.Publisher, goog.Disposable);


/**
 * Cache key for stored Publisher state.
 *
 * @type {string}
 * @private
 * @const
 */
rb.publish.Publisher.stateCacheKey_ = 'PublisherState';


/**
 * Set up an empty blog posting UI.
 */
rb.publish.Publisher.prototype.createNew = function() {
  var auth = /** @type {rb.auth.AuthManager} */ (this.sp_.getAuthManager());
  auth.getCurrentUser(goog.bind(this.renderNew_, this));
};


/**
 * Got the user.  Render the form.
 * @param {rb.auth.User} user The user.
 * @private
 */
rb.publish.Publisher.prototype.renderNew_ = function(user) {
  /**
   * @type {rb.auth.User}
   * @private
   */
  this.user_ = user;

  var sp = this.sp_,
      content = sp.getContentRoot(),
      cache = sp.getCache();
  content.innerHTML = rb.publish.templates.createNew({author: user.getName()});

  var form = goog.dom.getElement('rb-publish'),
      handler = /** @type {goog.events.EventHandler} */ (this.handler_);

  handler.listen(form, goog.events.EventType.SUBMIT, this.onSubmit_);

  var state = cache.get(rb.publish.Publisher.stateCacheKey_);
  if (state) {
    form['post-title'].value = state.title;
    form['post-content'].value = state.content;
  }
};


/**
 * Handles the form's onSubmit event.
 * @param {goog.events.BrowserEvent} e The onSubmit event.
 *
 * @private
 */
rb.publish.Publisher.prototype.onSubmit_ = function(e) {
  var rpc = this.sp_.getRPCService(),
      form = e.target;

  form['submit'].disabled = true;

  var post = new rb.post.BlogPost(form['post-title'].value,
                                  form['post-content'].value,
                                  this.user_.asAuthor()),
      onSuccess = goog.bind(this.onPostingSuccess_, this, post),
      onFailure = goog.bind(this.onPostingFailure_, this),
      cmd = new rb.publish.PublishCommand(onSuccess, onFailure, post);

  rpc.execute(cmd);
  e.preventDefault();
};


/**
 * The onSuccess callback given to PublishCommand.
 *
 * @param {rb.post.BlogPost} post The post that was posted.  This is bound to
 *    the callback, not passed by the PublishCommand.
 * @param {string} slug The unique slug for the posted blog entry.  This is
 *    passed by the PublishCommand.
 * @private
 */
rb.publish.Publisher.prototype.onPostingSuccess_ = function(post, slug) {
  var eventBus = this.sp_.getEventBus(),
      e = new rb.post.PostEvent(rb.post.EventType.CREATED, post);

  eventBus.dispatchEvent(e);
  relief.utils.setLocationHash('/post/' + slug);
};


/**
 * The onFailure callback given to PublishCommand.
 *
 * @param {rb.publish.PublishCommand.Response} status The error status.
 * @private
 */
rb.publish.Publisher.prototype.onPostingFailure_ = function(status) {
  var message;
  switch (status) {
    case rb.publish.PublishCommand.Response.AUTHENTICATION_ERROR:
      message = 'Posting error: You are not posting as you.';
      break;
    case rb.publish.PublishCommand.Response.CHECKSUM_MISMATCH:
      message = 'Posting error: Post contents corrupted during transmission.';
      break;
    case rb.publish.PublishCommand.Response.DATASTORE_ERROR:
      message = 'Posting error: Datastore error while saving post.';
      break;
    case rb.publish.PublishCommand.Response.UNAUTHORIZED:
      message = 'Posting error: You are not an administrator.';
      break;
    default:
      message = 'Unknown posting error.  Please try again later.';
      break;
  }

  alert(message);
  var form = goog.dom.getElement('rb-publish');
  form['submit'].disabled = false;
};


/**
 * Tears down the publisher UI.  Saves the current work into the cache so that
 * if the author returns, they see the form populated as it was when they
 * left.
 */
rb.publish.Publisher.prototype.tearDown = function() {
  var cache = this.sp_.getCache();

  var form = goog.dom.getElement('rb-publish'),
      title = form['post-title'].value,
      content = form['post-content'].value;

  if (title !== '' || content !== '') {
    cache.set(rb.publish.Publisher.stateCacheKey_, {
      title: title,
      content: content
    });
  }
  this.handler_.removeAll();
  this.sp_.getContentRoot().innerHTML = '';
};


/**
 * @inheritDoc
 */
rb.publish.Publisher.prototype.disposeInternal = function() {
  this.handler_.dispose();
  this.handler_ = this.sp_ = null;
};
